package com.oweight.sagacious.auth.client.interceptor;

import com.oweight.sagacious.auth.client.annotation.IgnoreClientToken;
import com.oweight.sagacious.auth.client.config.ServiceAuthConfig;
import com.oweight.sagacious.auth.client.jwt.ServiceAuthUtil;
import com.oweight.sagacious.auth.common.util.jwt.IJWTInfo;
import com.oweight.sagacious.common.exception.auth.ClientForbiddenException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 服务鉴权拦截器
 *
 * @author SAGE
 * @version v1 2019/10/19 14:26
 */
public class ServiceAuthRestInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private ServiceAuthUtil serviceAuthUtil;

    @Autowired
    private ServiceAuthConfig serviceAuthConfig;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HandlerMethod handlerMethod;

        if (!(handler instanceof HandlerMethod)) {
            // spring boot 2.0对静态资源也进行了拦截，当拦截器拦截到请求之后，
            // 但controller里并没有对应的请求时，该请求会被当成是对静态资源的请求。
            // 此时的handler就是 ResourceHttpRequestHandler，就会抛出上述错误。
            return super.preHandle(request, response, handler);
        }
        handlerMethod = (HandlerMethod) handler;

        // 配置该注解，说明不进行服务拦截
        IgnoreClientToken annotation = handlerMethod.getBeanType().getAnnotation(IgnoreClientToken.class);
        if (annotation == null) {
            annotation = handlerMethod.getMethodAnnotation(IgnoreClientToken.class);
        }
        if (annotation != null) {
            return super.preHandle(request, response, handler);
        }

        String token = request.getHeader(serviceAuthConfig.getTokenHeader());

        // 解析获取当前发起请求的服务
        IJWTInfo infoFromToken = serviceAuthUtil.getInfoFromToken(token);
        String uniqueName = infoFromToken.getUniqueName();

        // 判断当前被调⽤用服务的可被访问服务列列表是否包含当前发起请求的服务
        for (String client : serviceAuthUtil.getAllowedClient()) {
            if (client.equals(uniqueName)) {
                return super.preHandle(request, response, handler);
            }
        }
        throw new ClientForbiddenException("客户端（" + uniqueName.toUpperCase() + "）未授权!");
    }
}
